package com.justgame.project.cloud.common.util;


import com.auth0.jwt.JWT;
import com.justgame.project.cloud.common.entity.BaseEntity;
import com.justgame.project.cloud.common.constant.Auth2Token;
import com.justgame.project.cloud.common.constant.Const;
import com.justgame.project.cloud.common.exception.Exc;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.UnavailableSecurityManagerException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;

/**
 * Shiro工具
 */
@Slf4j
@Component
public class ShiroUtils {

    private static final RedisUtil redisUtil = AppContextUtils.getBean(RedisUtil.class);

    public static Session getSession() {
        return SecurityUtils.getSubject().getSession();
    }

    public static Subject getSubject() {
        return SecurityUtils.getSubject();

    }

    public static Object getUserEntity() {
        try {
            return SecurityUtils.getSubject().getPrincipal();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 判断登陆人是否市Admin
     *
     * @return boolean
     */
    public static Boolean isAdmin() {
        Object user = getUserEntity();
        if (ObjUtil.checkId(user)) {
            try {
                return Boolean.valueOf(BeanUtils.getProperty(user, "is_admin"));
            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                return false;
            }
        }
        return false;
    }

    public static String getUserId(HttpServletRequest request) {
        Object user = getUserEntity();
        try {
            if (user == null) {
                String token = request.getHeader("token");
                return StringUtils.isBlank(token) ? null : JWT.decode(token).getClaims().get("userid").asString();
            }
            return BeanUtils.getProperty(user, "id");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getUserId() {
        try {
            Object user = getUserEntity();
            if (user == null) {
                HttpServletRequest request = HttpContextUtil.getHttpRequest();
                String token = request.getHeader("token");
                return StringUtils.isBlank(token) ? null : JWT.decode(token).getClaims().get("userid").asString();
            }
            return BeanUtils.getProperty(user, "id");
        } catch (UnavailableSecurityManagerException e) {
            /* 此为未登录后调用这个方法会报错 */
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static <T extends BaseEntity> void setEntityUserId(T entity) {
        String userId = getUserId();
        if (userId == null) throw new Exc(Const.CODE_TOKEN_OUTDATED_CHINESE, Const.CODE_TOKEN_OUTDATED);
        entity.setCreateUser(userId);
    }

    public static void setSessionAttribute(Object key, Object value) {
        getSession().setAttribute(key, value);
    }

    public static Object getSessionAttribute(Object key) {
        try {
            return getSession().getAttribute(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void login(String token) {
        Subject subject = getSubject();
        subject.login(new Auth2Token(token));
    }

    public static boolean isLogin() {
        try {
            return SecurityUtils.getSubject().getPrincipal() != null;
        } catch (UnavailableSecurityManagerException e) {
            /* 此为未登录后调用这个方法会报错 */
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static String getKaptcha(String key) {
        Object kaptcha = getSessionAttribute(key);
        if (kaptcha == null) {
            throw new Exc("验证码已失效，请重新获取。");
        }
        getSession().removeAttribute(key);
        return kaptcha.toString();
    }

    public static String getToken() {
        try{
            return HttpContextUtil.getHttpRequest().getHeader("token");
        }catch (NullPointerException e){
            return null;
        }
    }

    public static String BuildRedisTokenKey(String Token) {
        return Const.KEY_REDIS_TOKEN_HEAD + Token;
    }

    public static String BuildRedisTokenCurrentKey(String uid) {
        return Const.KEY_REDIS_TOKEN_CURRENT + uid;
    }

    public static String getUidByToken(String token) {
        return redisUtil.get(BuildRedisTokenKey(token));
    }

    public static Long getExpireByToken(String token) {
        return redisUtil.getExpire(BuildRedisTokenKey(token));
    }

    public static void delToken(String token) {
        redisUtil.delete(BuildRedisTokenKey(token));
    }

    public static void delToken(String token,String uid) {
        redisUtil.delete(BuildRedisTokenKey(token));
        redisUtil.delete(BuildRedisTokenCurrentKey(uid));
    }

    public static void delCurrentToken(String uid) {
        redisUtil.delete(BuildRedisTokenCurrentKey(uid));
    }

    public static void addToken(String token, String uid) {
        redisUtil.set(BuildRedisTokenKey(token), uid, Const.TIME_TIMEOUT_TOKEN);
        redisUtil.set(BuildRedisTokenCurrentKey(uid), token, Const.TIME_TIMEOUT_TOKEN);
    }

    public static boolean isExpiredToken(String token, String uid) {
        String CurrentToken = redisUtil.get(BuildRedisTokenCurrentKey(uid));
        // 判断 current_token 和当前 token 是否匹配
        if (CurrentToken != null && CurrentToken.equals(token)) {
            //        获取传入的Token 是否本身已过期
            return getExpireByToken(token) <= 0;
        } else {
            return true;
        }
    }
}
